use serde::{Deserialize, Serialize};

use crate::{
    prelude::{Column, table_props::TableProps},
    structs::{FliterItems, report::ParamSelected},
};

use super::DataType;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColumnCells {
    column_cells: Vec<Vec<ColumnCell>>,
    leafs: Vec<(usize, usize)>,
}
impl ColumnCells {
    pub fn from(column_cells: Vec<Vec<ColumnCell>>, leafs: Vec<(usize, usize)>) -> Self {
        Self {
            column_cells,
            leafs,
        }
    }
    pub fn from_columns(cols: &Vec<Column>, dsiplay_clos: &Vec<&str>) -> Self {
        let cells = create_header_cells2(cols, dsiplay_clos);
        cells
    }
    pub fn from_columncells(cols: Vec<ColumnCell>, dsiplay_clos: &Vec<&str>) -> Self {
        let cells = create_header_cells(cols, dsiplay_clos);
        cells
    }
    pub fn get_position(&self, name: &str) -> Option<usize> {
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.name.as_str() == name {
                    return Some(*j);
                }
            }
        }
        None
    }
    pub fn is_no_title(&self, idx: usize) -> bool {
        if let Some(ColumnCell::Leaf(leaf)) = self.column_cells[0].get(idx) {
            return leaf.title.is_none();
        }
        false
    }
    pub fn get_not_show_indexs(&self) -> Vec<usize> {
        let mut res: Vec<usize> = Vec::new();
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.title.is_none() {
                    res.push(*j);
                }
            }
        }
        res
    }
    pub fn get_column_cells(&self) -> Vec<Vec<&ColumnCell>> {
        let mut res: Vec<Vec<&ColumnCell>> = Vec::new();
        let mut idxs: Vec<usize> = Vec::new();
        for (i, c) in self.column_cells[0].iter().enumerate() {
            if let ColumnCell::Leaf(l) = c {
                if l.title.is_none() {
                    idxs.push(i);
                }
            }
        }
        for i in 0..self.column_cells.len() {
            let mut row: Vec<&ColumnCell> = Vec::new();
            for j in 0..self.column_cells[i].len() {
                if idxs.contains(&j) {
                    continue;
                }
                row.push(&self.column_cells[i][j]);
            }
            res.push(row);
        }
        res
    }
    pub fn get_leaf_cells(&self) -> Vec<&ColumnCellLeaf> {
        let mut res: Vec<&ColumnCellLeaf> = Vec::new();
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.title.is_some() {
                    res.push(leaf);
                }
            }
        }
        res
    }
    pub fn get_leaf_cell_by_name(&self, name: &str) -> Option<&ColumnCellLeaf> {
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.name.as_str() == name {
                    return Some(leaf);
                }
            }
        }
        None
    }
    pub fn is_leaf(&self, name: &str) -> bool {
        for leaf in self.get_leaf_cells() {
            if leaf.name.as_str() == name {
                return true;
            }
        }
        false
    }
    pub fn get_leaf_cell(&self, col_name: &str) -> Option<&ColumnCellLeaf> {
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.name.as_str() == col_name {
                    return Some(leaf);
                }
            }
        }
        None
    }
    pub fn get_leaf_cell_by_idx(&self, idx: usize) -> Option<&ColumnCellLeaf> {
        for (i, j) in self.leafs.iter() {
            if j == &idx {
                if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                    return Some(leaf);
                }
            }
        }
        None
    }
    pub fn get_show_leaf_cell_by_idx(&self, idx: usize) -> Option<&ColumnCellLeaf> {
        let mut index=0usize;
        for (i, j) in self.leafs.iter() {
            if let ColumnCell::Leaf(leaf) = &self.column_cells[*i][*j] {
                if leaf.title.is_some() {
                    if index == idx {
                        return Some(leaf);
                    }
                    index += 1;
                }
            }
        }
        None
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColumnCellBranch {
    pub title: String,
    pub children: Vec<ColumnCell>,
    pub colspan: u8,
    pub rowspan: u8,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColumnCellLeaf {
    pub name: String,
    pub title: Option<String>,
    pub colspan: u8,
    pub rowspan: u8,
    pub data_type: DataType,
    pub list_props: Option<TableProps>,
    pub dict_col_name: Option<String>,
    pub front_must: bool,
    pub is_null: bool,
    #[serde(default)]
    pub default_filter: Option<FliterItems>,
    pub param_selected: Option<ParamSelected>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ColumnCell {
    Leaf(ColumnCellLeaf),
    Branch(ColumnCellBranch),
    None,
}
impl ColumnCell {
    pub fn as_leaf(&self) -> Option<&ColumnCellLeaf> {
        if let ColumnCell::Leaf(leaf) = self {
            return Some(leaf);
        }
        None
    }
    pub fn as_branch(&self) -> Option<&ColumnCellBranch> {
        if let ColumnCell::Branch(branch) = self {
            return Some(branch);
        }
        None
    }
}
fn create_header_cells(cols: Vec<ColumnCell>, dsiplay_clos: &Vec<&str>) -> ColumnCells {
    let mut max_deep: u8 = 0;
    let mut deeps: Vec<u8> = Vec::new();
    for col in cols.iter() {
        let deep = get_column_deep(col, &dsiplay_clos);
        deeps.push(deep);
        if deep > max_deep {
            max_deep = deep;
        }
    }
    let mut trs: Vec<Vec<ColumnCell>> = Vec::new();
    let mut leafs: Vec<(usize, usize)> = Vec::new();
    (0..max_deep).into_iter().for_each(|_| trs.push(Vec::new()));
    for (i, col) in cols.into_iter().enumerate() {
        get_header_cells(
            col,
            0,
            deeps[i],
            max_deep,
            &mut trs,
            &mut leafs,
            dsiplay_clos,
        );
    }
    ColumnCells {
        column_cells: trs,
        leafs,
    }
}
fn create_header_cells2(cols: &Vec<Column>, dsiplay_clos: &Vec<&str>) -> ColumnCells {
    let mut max_deep: u8 = 0;
    let mut deeps: Vec<u8> = Vec::new();
    for col in cols.iter() {
        let deep = get_column_deep2(col, &dsiplay_clos);
        deeps.push(deep);
        if deep > max_deep {
            max_deep = deep;
        }
    }
    let mut trs: Vec<Vec<ColumnCell>> = Vec::new();
    let mut leafs: Vec<(usize, usize)> = Vec::new();
    (0..max_deep).into_iter().for_each(|_| trs.push(Vec::new()));
    for (i, col) in cols.into_iter().enumerate() {
        get_header_cells2(
            col,
            0,
            deeps[i],
            max_deep,
            &mut trs,
            &mut leafs,
            dsiplay_clos,
        );
    }
    ColumnCells {
        column_cells: trs,
        leafs,
    }
}
fn get_header_cells(
    col: ColumnCell,
    row_number: usize,
    deep: u8,
    max_deep: u8,
    cells: &mut Vec<Vec<ColumnCell>>,
    leafs: &mut Vec<(usize, usize)>,
    dsiplay_clos: &Vec<&str>,
) {
    let leafs_count = get_column_leafs_count(&col, dsiplay_clos);
    if leafs_count == 0 {
        return;
    }
    let mut rowspan = 1_u8;
    match col {
        ColumnCell::Leaf(leaf) => {
            rowspan += max_deep - deep;
            let mut leaf = leaf.clone();
            leaf.rowspan = rowspan;
            cells[row_number].push(ColumnCell::Leaf(leaf));
            for i in 1..rowspan {
                cells[row_number + i as usize].push(ColumnCell::None);
            }
            leafs.push((row_number, cells[row_number].len() - 1));
        }
        ColumnCell::Branch(branch) => {
            let new_bran = ColumnCellBranch {
                title: branch.title.clone(),
                children: Vec::new(),
                colspan: leafs_count as u8,
                rowspan: branch.rowspan,
            };
            cells[row_number].push(ColumnCell::Branch(new_bran));
            let deep = row_number as u8 + 2;
            for ccol in branch.children.into_iter() {
                get_header_cells(
                    ccol,
                    row_number + 1,
                    deep,
                    max_deep,
                    cells,
                    leafs,
                    dsiplay_clos,
                );
            }
        }
        ColumnCell::None => {}
    }
}
fn get_header_cells2(
    col: &Column,
    row_number: usize,
    deep: u8,
    max_deep: u8,
    cells: &mut Vec<Vec<ColumnCell>>,
    leafs: &mut Vec<(usize, usize)>,
    dsiplay_clos: &Vec<&str>,
) {
    let leafs_count = get_column_leafs_count2(&col, dsiplay_clos);
    if leafs_count == 0 {
        return;
    }
    let mut rowspan = 1_u8;
    if col.children.len() == 0 {
        rowspan += max_deep - deep;
        let mut leaf = ColumnCellLeaf {
            name: col.name.clone().unwrap_or("".to_string()),
            title: col.title.clone(),
            colspan: 1,
            rowspan,
            data_type: col.data_type,
            list_props: col.list_props.clone(),
            dict_col_name: col.dict_col_name.clone(),
            front_must: col.is_pk,
            is_null: col.is_null,
            default_filter: col.default_filter.clone(),
            param_selected: None,
        };
        leaf.rowspan = rowspan;
        cells[row_number].push(ColumnCell::Leaf(leaf));
        for i in 1..rowspan {
            cells[row_number + i as usize].push(ColumnCell::None);
        }
        leafs.push((row_number, cells[row_number].len() - 1));
    } else {
        let new_bran = ColumnCellBranch {
            title: col.title.clone().unwrap_or("".to_string()),
            children: Vec::new(),
            colspan: leafs_count as u8,
            rowspan: 1,
        };
        cells[row_number].push(ColumnCell::Branch(new_bran));
        let deep = row_number as u8 + 2;
        for ccol in col.children.iter() {
            get_header_cells2(
                ccol,
                row_number + 1,
                deep,
                max_deep,
                cells,
                leafs,
                dsiplay_clos,
            );
        }
    }
}

fn is_display_column(col: &ColumnCell, dsiplay_clos: &Vec<&str>) -> bool {
    match col {
        ColumnCell::Leaf(leaf) => {
            return dsiplay_clos.contains(&leaf.name.as_str());
        }
        ColumnCell::Branch(branch) => {
            for ccol in branch.children.iter() {
                if is_display_column(ccol, dsiplay_clos) {
                    return true;
                }
            }
        }
        ColumnCell::None => {
            return false;
        }
    }
    false
}
fn is_display_column2(col: &Column, display_clos: &Vec<&str>) -> bool {
    let display = if col.children.len() == 0 {
        let name = col.name.as_ref().map(|n| n.as_str()).unwrap_or("");
        display_clos.contains(&name)
    } else {
        for ccol in col.children.iter() {
            if is_display_column2(ccol, display_clos) {
                return true;
            }
        }
        false
    };
    display
}

fn get_column_deep(col: &ColumnCell, dsiplay_clos: &Vec<&str>) -> u8 {
    if !is_display_column(col, dsiplay_clos) {
        return 0;
    }
    match col {
        ColumnCell::Leaf(_leaf) => {
            return 1;
        }
        ColumnCell::Branch(branch) => {
            let mut deep = 0_u8;
            for ccol in branch.children.iter() {
                let d2 = get_column_deep(ccol, dsiplay_clos);
                if d2 > deep {
                    deep = d2;
                }
            }
            return deep + 1;
        }
        ColumnCell::None => 0,
    }
}
fn get_column_deep2(col: &Column, dsiplay_clos: &Vec<&str>) -> u8 {
    if !is_display_column2(col, dsiplay_clos) {
        return 0;
    }
    if col.children.len() == 0 {
        return 1;
    } else {
        let mut deep = 0_u8;
        for ccol in col.children.iter() {
            let d2 = get_column_deep2(ccol, dsiplay_clos);
            if d2 > deep {
                deep = d2;
            }
        }
        return deep + 1;
    }
}

fn get_column_leafs_count(col: &ColumnCell, dsiplay_clos: &Vec<&str>) -> usize {
    if !is_display_column(col, dsiplay_clos) {
        return 0;
    }
    let mut count = 0_usize;
    match col {
        ColumnCell::Leaf(_leaf) => {
            return 1;
        }
        ColumnCell::Branch(branch) => {
            for ccol in branch.children.iter() {
                count += get_column_leafs_count(ccol, dsiplay_clos);
            }
        }
        ColumnCell::None => {}
    }
    count
}

fn get_column_leafs_count2(col: &Column, dsiplay_clos: &Vec<&str>) -> usize {
    if !is_display_column2(col, dsiplay_clos) {
        return 0;
    }
    let mut count = 0_usize;
    if col.children.len() == 0 {
        return 1;
    }
    for ccol in col.children.iter() {
        count += get_column_leafs_count2(ccol, dsiplay_clos);
    }
    count
}
